package edu.pitt.cs.cs2510.project3.model;

/*
 * File: Server.java
 * Authors: Jesse Szwedko, Callen Shaw, Heather Friedberg
 * CS2510 Project 3
 */

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import edu.pitt.cs.cs2510.project3.configuration.InputParameters;
//import edu.pitt.cs.cs2510.project3.model.replication.CopyReplication;
//import edu.pitt.cs.cs2510.project3.model.replication.DeleteReplication;
import edu.pitt.cs.cs2510.project3.model.replication.Replication;

public abstract class Server extends Thread{
	protected int id;
	public Map<Integer, File> files;
	protected InputParameters simulationParameters;
	public Queue<Request> requests;
	public List<Request> completedRequests;
	public List<Replication> replications;
	
	public static int deletions = 0;
	public int time;
	public boolean die = false; //signal to end execution
	public boolean tick; //whether or not the clock has been advance
	
	//will be set to true when there aren't going to be any more requests from clients; servers should wrap up when this is true and queues are empty
	protected boolean noMoreRequests = false;
	protected List<String> requestedFilenames;
	
	protected Object monitor;
	
	public Server(int id, InputParameters simulationParameters, Object monitor) {
		this.id = id;
		
		this.files = new HashMap<Integer, File>();		
		this.requests = new ConcurrentLinkedQueue<Request>();
		this.completedRequests = new ArrayList<Request>();
		this.replications = new ArrayList<Replication>();
		this.requestedFilenames = new ArrayList<String>();
		this.simulationParameters = simulationParameters;
		this.monitor = monitor;
	}
	
	public void addRequest(Request request)
	{
		this.requests.add(request);
	}
	
	

	protected int getServerDistance(Server server, Server server2) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	protected abstract void wakeUp();

	public int remainingSpace() {
		int remainingSpace = this.simulationParameters.getStorageSize();
		
		for (File file : this.files.values())
		{
			remainingSpace -= file.size;
		}
		
		return remainingSpace;
	}
	
	protected abstract double getUptimeCost();
	
	/**
	 * @return Returns true if the server is ready to shutdown
	 */
	public abstract boolean isDone();
	
	/**
	 * @return Returns true if the server is in an idle state (e.g. no pending requests)
	 */
	abstract public boolean isReady();

	public boolean hasFile(int fileId) {
		return this.files.keySet().contains(fileId);
	}

	public boolean hasFileBlock(int fileId, int blockId) {
		return this.files.keySet().contains(fileId) && (blockId >= (this.files.get(fileId).size - this.files.get(fileId).numBlocks));
	}
	
	@Override
	public String toString() {
		return "Server [id=" + id + ", files=" + files
				+ ", requests=" + requests + ", completedRequests="
				+ completedRequests + ", replications=" + replications
				+ ", time=" + time + ", die=" + die + ", tick=" + tick
				+ ", noMoreRequests=" + noMoreRequests
				+ ", requestedFilenames=" + requestedFilenames + "]";
	}

	abstract public void noMoreRequests(boolean noMoreRequests);
	
	public abstract String getUniqueIdentifier();

	public abstract void die();
	
	public long getId(){return id;}
}